import fs from "fs"
import path from "path"
import yaml from "yaml"
import { Config } from "#components"
import { Button } from "#model"
import { REG } from "./index.js"
import { logger } from "#lib"
import qrcode from "qrcode"

const signApi = `http://localhost:${Config.Bili.Server_Port}/bili`

const login = "(扫码)?(登陆|登录)"
const restart = "刷新[Cc][Kk]"
const out = "退出"

const loginReg = new RegExp(`^#?${REG}${login}$|^#?${login}${REG}$`)
const restartReg = new RegExp(`^#?${REG}${restart}$`)
const outReg = new RegExp(`^#?${REG}${out}$|^#?${out}${REG}$`)

export class Bililogin extends plugin {
  constructor() {
    super({
      name: "Y:B站登录",
      desc: "登录",
      event: "message",
      priority: Config.other.priority,
      rule: [
        {
          reg: loginReg,
          fnc: "login"
        },
        {
          reg: restartReg,
          fnc: "restart"
        },
        {
          reg: outReg,
          fnc: "out"
        }
      ]
    })
  }

  async login(e) {
    if (await redis.get(`login:${e.user_id}`)) return e.reply("前置二维码未失效，请稍后尝试", true)
    const storageDir = "./data/bili"
    if (!fs.existsSync(storageDir)) {
      fs.mkdirSync(storageDir, { recursive: true })
    }
    try {
      const loginkey = `${e.user_id}:${e.self_id}`
      await redis.set(`login:${e.user_id}`, "pending", "EX", 300)
      const qrRes = await fetch(`${Config.Bili.Sign_Api}/login?t=bili`)
      const qrInfo = await qrRes.json()
      if (qrInfo.code !== 0 || !qrInfo.data) throw new Error(`获取二维码信息失败: ${qrInfo.msg || "未知错误"}`)
      const { url, auth_code } = qrInfo.data
      let qrBuffer
      try {
        qrBuffer = await qrcode.toBuffer(url, {
          errorCorrectionLevel: "M",
          margin: 1,
          width: 200
        })
        await e.reply(["请扫描下方二维码登录B站（有效期1分钟）：", segment.image(qrBuffer)], true)
      } catch (qrError) {
        logger.error("生成二维码失败：", qrError)
        await e.reply("生成二维码失败，请稍后再试", true)
        await redis.del(`login:${e.user_id}`)
        return
      }
      let isSuccess = false
      let pollCount = 0
      const maxPollCount = 30
      const pollInterval = 2000

      while (pollCount < maxPollCount && !isSuccess) {
        try {
          await new Promise((resolve) => setTimeout(resolve, pollInterval))
          pollCount++
          const pollRes = await fetch(`${Config.Bili.Sign_Api}/login?t=bilipoll&auth_code=${auth_code}&key=${loginkey}`)
          const pollData = await pollRes.json()
          if (pollData.code === 0 && pollData.data) {
            isSuccess = true
            await this.handleLoginSuccess(pollData.data, e)
            break
          }
          if (pollData.code === 86038) {
            await e.reply("二维码已过期，请重新获取", true)
            break
          }
        } catch (pollError) {
          logger.error("登录轮询失败：", pollError)
          await e.reply("登录验证失败，请重试", true)
          break
        }
      }
      if (!isSuccess && pollCount >= maxPollCount) {
        await e.reply("登录超时，请重新获取二维码", true)
      }
    } catch (error) {
      logger.error("登录流程失败：", error)
      await e.reply("获取二维码失败，请稍后再试", true)
    } finally {
      await redis.del(`login:${e.user_id}`)
    }
  }

  async handleLoginSuccess(data, e) {
    try {
      const newUserData = {
        access_token: data.access_token,
        SESSDATA: data.cookie.SESSDATA,
        csrf: data.cookie.bili_jct,
        DedeUserID: data.cookie.DedeUserID,
        DedeUserID__ckMd5: data.cookie.DedeUserID__ckMd5,
        sid: data.cookie.sid,
        refresh_token: data.refresh_token,
        expires_in: Date.now() + data.expires_in * 1000,
        LoginGroup: e.group_id
      }

      const storageDir = "./data/bili"
      const filePath = path.join(storageDir, `${e.user_id}.yaml`)
      let existingData = {}
      if (fs.existsSync(filePath)) {
        const existingContent = fs.readFileSync(filePath, "utf8")
        existingData = yaml.parse(existingContent) || {}
      }
      const targetUserId = data.cookie.DedeUserID
      const mergedData = {
        ...existingData,
        [targetUserId]: existingData[targetUserId] ? { ...existingData[targetUserId], ...newUserData } : newUserData // 不存在则直接新增
      }
      const yamlString = yaml.stringify(mergedData, {
        indent: 2,
        simpleKeys: true
      })
      fs.writeFileSync(filePath, yamlString, "utf8")
      logger.info(`用户 ${e.user_id} B站登录成功（${existingData[targetUserId] ? "覆盖" : "新增"}账号：${targetUserId}`)
      await e.reply(`登录成功！欢迎回来，用户ID：${data.mid}`, true)
    } catch (saveError) {
      logger.error("登录数据存储失败：", saveError)
      await e.reply("登录成功，但数据存储失败，请联系管理员", true)
    }
  }

  async restart(e) {
    const cookieFile = path.join(`./data/bili/${e.user_id}.yaml`)
    if (!fs.existsSync(cookieFile)) {
      return await e.reply("未绑定ck，请发送【B站登录】进行绑定", true)
    }
    let cookiesData = yaml.parse(fs.readFileSync(cookieFile, "utf8"))
    const updatedCookies = {}
    const successMessages = []
    for (const dedeUserId in cookiesData) {
      const userCookies = cookiesData[dedeUserId]
      const restartUrl = `${signApi}/refresh?accesskey=${userCookies.access_token}&refresh_token=${userCookies.refresh_token}`
      try {
        const restartData = await fetch(restartUrl)
        if (!restartData.ok) {
          throw new Error(`请求失败，状态码: ${restartData.status}`)
        }
        const data = await restartData.json()

        const ts = Math.floor(Date.now() / 1000)
        const expires = data.data.token_info.expires_in
        const ationTime = ts * 1000 + expires * 1000

        const excludedKeys = [
          "access_token",
          "SESSDATA",
          "csrf",
          "DedeUserID",
          "DedeUserID__ckMd5",
          "sid",
          "refresh_token",
          "expires_in",
          "LoginGroup"
        ]
        const additionalParams = {}
        for (const key in userCookies) {
          if (!excludedKeys.includes(key)) {
            additionalParams[key] = userCookies[key]
          }
        }

        const updatedCookie = {
          access_token: data.data.token_info.access_token,
          SESSDATA: data.data.cookie_info.cookies.find((c) => c.name === "SESSDATA")?.value,
          csrf: data.data.cookie_info.cookies.find((c) => c.name === "bili_jct")?.value,
          DedeUserID: data.data.cookie_info.cookies.find((c) => c.name === "DedeUserID")?.value,
          DedeUserID__ckMd5: data.data.cookie_info.cookies.find((c) => c.name === "DedeUserID__ckMd5")?.value,
          sid: data.data.cookie_info.cookies.find((c) => c.name === "sid")?.value,
          refresh_token: data.data.token_info.refresh_token,
          expires_in: ationTime,
          LoginGroup: e.group_id,
          ...additionalParams
        }

        updatedCookies[dedeUserId] = updatedCookie
        successMessages.push(`账号${successMessages.length + 1}：${dedeUserId}`)
      } catch (err) {
        logger.error(`刷新Token失败 (DedeUserID: ${dedeUserId}):`, err)
        e.reply(`B站CK更新失败 (DedeUserID: ${dedeUserId})`, true)
      }
    }
    try {
      const updatedContent = yaml.stringify(updatedCookies)
      fs.writeFileSync(cookieFile, updatedContent, "utf8")
      const successReply = `B站CK刷新成功\n${successMessages.join("\n")}`
      e.reply([successReply, new Button().help()], true)
    } catch (err) {
      logger.error("无法写入cookie文件:", err)
      e.reply("B站CK刷新失败", true)
    }
  }

  async out(e) {
    const cookieFile = path.join(`./data/bili/${e.user_id}.yaml`)
    if (!fs.existsSync(cookieFile)) {
      return await e.reply("未绑定ck，请发送【B站登录】进行绑定", true)
    }
    let cookiesData = yaml.parse(await fs.promises.readFile(cookieFile, "utf8"))
    const userIds = Object.keys(cookiesData)
    let currentUserId = await redis.get(`Y:Bili:userset:${e.user_id}`)
    if (!userIds.includes(currentUserId)) {
      currentUserId = userIds[0]
      await redis.set(`Y:Bili:userset:${e.user_id}`, currentUserId)
    }
    const deleteUserId = currentUserId
    delete cookiesData[deleteUserId]
    if (Object.keys(cookiesData).length === 0) {
      await fs.promises.unlink(cookieFile)
      await redis.del(`Y:Bili:userset:${e.user_id}`)
      e.reply("B站账号已全部退出", true)
    } else {
      const newCurrentUserId = Object.keys(cookiesData)[0]
      await redis.set(`Y:Bili:userset:${e.user_id}`, newCurrentUserId)
      const updatedContent = yaml.stringify(cookiesData)
      await fs.promises.writeFile(cookieFile, updatedContent, "utf8")
      const replyMsg =
        `账号 ${deleteUserId} 成功退出登录\n剩余账号:\n` +
        Object.keys(cookiesData)
          .map((id) => `${id} ${id === newCurrentUserId ? "√" : ""}`)
          .join("\n")
      e.reply([replyMsg.trim(), new Button().help()], true)
    }
  }
}
